﻿using Fleck;
using System.Collections.Concurrent;

namespace FleckDemo
{
    public class WebSocket
    {
        // 这里服务端用的是广播发送,如果要点对点(P2P),可以用Dictionary<string, IWebSocketConnection>,其中string存的是客户端id
        // 如果需要有顺序，也可以使使用元素列表:List<(string clientId, IWebSocketConnection websocket)>
        // 当然如果考虑线程安全性问题，还需要加lock、或者使用线程安全的集合
        //private List<IWebSocketConnection> allSockets = new List<IWebSocketConnection>();

        IDictionary<string, IWebSocketConnection> dic_Sockets = new ConcurrentDictionary<string, IWebSocketConnection>();


        public void WebStart()
        {
            FleckLog.Level = LogLevel.Debug;

            WebSocketServer server = new WebSocketServer("ws://0.0.0.0:2000/");
            // 出错后进行重启
            server.RestartAfterListenError = true;
            // 开始监听
            server.Start(socket =>
            {
                socket.OnOpen = () =>  // 连接建立事件
                {
                    Console.WriteLine("Open!");
                    // 获取ip:port
                    string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
                    dic_Sockets.Add(clientUrl, socket);
                    Console.WriteLine("当前客户端数:" + dic_Sockets.Count);
                };
                socket.OnClose = () =>  // 连接关闭事件
                {
                    Console.WriteLine("Close!");
                    string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
                    // 如果存在这个客户端,那么对这个socket进行移除
                    if (dic_Sockets.ContainsKey(clientUrl))
                    {
                        // Fleck库自己会释放这个client连接
                        dic_Sockets.Remove(clientUrl);
                    }

                    Console.WriteLine("当前客户端数:"+dic_Sockets.Count);
                };
                socket.OnMessage = message =>  // 接收客户端消息事件(消息文本utf-8(string/json字符串)或二进制(byte))
                {
                    try
                    {
                        Console.WriteLine(message);

                        // 点对点私发
                        string clientUrl = socket.ConnectionInfo.ClientIpAddress + ":" + socket.ConnectionInfo.ClientPort;
                        // 把消息,回显给发给我的客户端
                        Send(clientUrl, message);
                        // allSockets.ToList().ForEach(s => s.Send("Echo: " + message));
                    }
                    catch (Exception e)
                    {
                        // 立即反馈异常信息
                        Console.WriteLine(e.Message);
                        Console.WriteLine(e.StackTrace);
                    }
                };
                socket.OnError = e =>
                {
                    Console.WriteLine(e.Message);
                    Console.WriteLine(e.StackTrace);
                };
            });
        }

        ///// <summary>
        /// 按字节发送(点对点发送)
        /// </summary>
        /// <param name="vlue"></param>
        public void Send(string clientUrl, byte[] vlue)
        {
            if (dic_Sockets.TryGetValue(clientUrl, out IWebSocketConnection client))
            {
                client.Send(vlue);
            }
        }

        /// <summary>
        /// 按字符串发送(点对点发送)
        /// </summary>
        /// <param name="vlue"></param>
        public void Send(string clientUrl, string vlue)
        {
            if (dic_Sockets.TryGetValue(clientUrl, out IWebSocketConnection client))
            {
                client.Send(vlue);
            }
        }

        ///// <summary>
        /// 按字节发送(群发【广播】)
        /// </summary>
        /// <param name="vlue"></param>
        public void Send(byte[] vlue)
        {
            foreach (KeyValuePair<string, IWebSocketConnection> item in dic_Sockets)
            {
                item.Value.Send(vlue);
            }
        }

        /// <summary>
        /// 按字符串发送(群发【广播】)
        /// </summary>
        /// <param name="vlue"></param>
        public void Send(string vlue)
        {
            foreach (KeyValuePair<string, IWebSocketConnection> item in dic_Sockets)
            {
                item.Value.Send(vlue);
            }
        }

    }
}
